package com.mftour.moudles;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.mftour.MapperConfig;

/**
 * 通过扫描mapper对应的class文件路径,找到每个mapper，然后依次执行所有方法，拦截器里面获取具体sql
 * 
 * @author Daqsoft
 *
 */
//@Component
public class InitRunner implements ApplicationRunner {

	@Autowired
	private ApplicationContext applicationContext;

	@Autowired
	private MapperConfig mapperConfig;

	protected final static Log logger = LogFactory.getLog(InitRunner.class);

	private static Map<String, String> commonMethodNameMap = new HashMap<String, String>();

	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("start init");

		List<String> mapperStrList = getObjecsInPackage(mapperConfig.getPath(), true);

		mapperStrList.removeIf(new Predicate<String>() {

			@Override
			public boolean test(String t) {
				String className = t.substring(t.lastIndexOf(".") + 1).toLowerCase();
				for (String excludeName : mapperConfig.getExcludes()) {
					if (className.equals(excludeName)) {
						return true;
					}
				}
				return false;
			}

		});

		Method[] ms = Object.class.getMethods();
		for (Method method : ms) {
			commonMethodNameMap.put(getMethodParmName(method), "t");
		}

		for (String mapperName : mapperStrList) {
			Class<?> c = Class.forName(mapperName);
			Object o = applicationContext.getBean(c);

			for (Method method : c.getMethods()) {
				if (isCustomerMethod(method)) {
					int len = method.getParameterCount();
					Object[] ps = new Object[len];
					try {
						method.invoke(o, ps);
					} catch (Exception e) {
//						e.printStackTrace();
					}
				}
			}

			System.out.println(o.getClass());

		}

		System.exit(1);
	}

	private static String getMethodParmName(Method method) {
		String name = method.getName();
		String ptypes = "";
		if (method.getParameterTypes().length > 0) {
			for (Class<?> c : method.getParameterTypes()) {
				ptypes = ptypes + "," + c.getName();
			}
		}
		name = name + ptypes;
		return name;
	}

	/**
	 * 不会去找父类，不会找到object的相关方法，可以无需判断?
	 * @param method
	 * @return
	 */
	public static boolean isCustomerMethod(Method method) {
		if (commonMethodNameMap.get(getMethodParmName(method)) != null) {
			return false;
		} else {
			System.out.println(getMethodParmName(method));
			return true;
		}

	}

	public static List<String> getObjecsInPackage(String packageName, boolean includeFlag) {

		String packageDirName = packageName.replace(".", "/");
		Enumeration<URL> dirs = null;

		try {
			dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
			List<String> classList = new ArrayList<String>();
			// 迭代此Enumeration
			while (dirs.hasMoreElements()) {

				// 路径包含空格，url会编码，在转文件前需要解码不然获取不到文件
				URL url = dirs.nextElement();
				String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8.name());

				File file = new File(filePath);

				// 把目录下的所有文件列出
				File[] classes = file.listFiles();
				if (classes != null) {
					for (File f : classes) {
						if (f.isFile()) {
							// 截取.class
							if (f.getName().lastIndexOf(".class") != -1) {
								String qName = packageName + "." + f.getName().substring(0, f.getName().length() - 6);
								logger.debug("qName=" + qName);
								classList.add(qName);
							}
						} else if (f.isDirectory()) {
							if (includeFlag) {
								classList.addAll(getObjecsInPackage(packageName + "." + f.getName(), true));
							}
						}
					}
				}

			}
			return classList;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

}
